#include <iostream>
#include <string>
#include <unistd.h>
#include <pthread.h>

#define THREAD_NUM 4

// pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
// pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
typedef void (*func_t)(const std::string &threadName, pthread_mutex_t *pmtx, pthread_cond_t *pcond);
volatile bool quit = false;

class ThreadInfo
{
public:
    ThreadInfo(const std::string &threadName, func_t func, pthread_mutex_t *pmtx, pthread_cond_t *pcond)
        : _threadName(threadName),
          _startRoutine(func),
          _pmtx(pmtx),
          _pcond(pcond)
    {
    }

public:
    std::string _threadName;
    func_t _startRoutine;
    pthread_mutex_t *_pmtx;
    pthread_cond_t *_pcond;
};

void login(const std::string &threadName, pthread_mutex_t *pmtx, pthread_cond_t *pcond)
{
    while (!quit)
    {
        pthread_mutex_lock(pmtx);
        pthread_cond_wait(pcond, pmtx); // 线程刚开始执行 就调用wait 当前线程会被立即被阻塞
        std::cout << threadName << " running... -- login::登录" << std::endl;
        pthread_mutex_unlock(pmtx);
    }
}

void load(const std::string &threadName, pthread_mutex_t *pmtx, pthread_cond_t *pcond)
{
    while (!quit)
    {
        pthread_mutex_lock(pmtx);
        pthread_cond_wait(pcond, pmtx);
        std::cout << threadName << " running...  -- load::加载" << std::endl;
        pthread_mutex_unlock(pmtx);
    }
}

void download(const std::string &threadName, pthread_mutex_t *pmtx, pthread_cond_t *pcond)
{
    while (!quit)
    {
        pthread_mutex_lock(pmtx);
        pthread_cond_wait(pcond, pmtx);
        std::cout << threadName << " running...  -- download::下载" << std::endl;
        pthread_mutex_unlock(pmtx);
    }
}

void send(const std::string &threadName, pthread_mutex_t *pmtx, pthread_cond_t *pcond)
{
    while (!quit)
    {
        pthread_mutex_lock(pmtx);
        pthread_cond_wait(pcond, pmtx);
        std::cout << threadName << " running...  -- send::发送" << std::endl;
        pthread_mutex_unlock(pmtx);
    }
}

// 启动例程 --- 新线程入口函数
void *Entry(void *args)
{
    ThreadInfo *td = (ThreadInfo *)args;         // td在每一个线程自己私有的栈空间中保存
    td->_startRoutine(td->_threadName, td->_pmtx, td->_pcond); // td->_func是一个函数 调用完成后就会返回

    delete td;
    return nullptr;
}

int main()
{
    pthread_t tids[THREAD_NUM];
    func_t funcs[THREAD_NUM] = {login, load, download, send};

    pthread_mutex_t mtx;
    pthread_mutex_init(&mtx, nullptr);

    pthread_cond_t cond;
    pthread_cond_init(&cond, nullptr);

    // 创建THREAD_NUM个线程
    for (int i = 0; i < THREAD_NUM; i++)
    {
        std::string threadName = "Thread " + std::to_string(i + 1);
        ThreadInfo *td = new ThreadInfo(threadName, funcs[i], &mtx, &cond);

        pthread_create(tids + i, nullptr, Entry, (void *)td);
    }

    // 观察：主线程创建了新线程 新线程都在wait
    // 主线程也不去唤醒 此时应该是一个没有线程在做事的空窗期
    sleep(2);

    // 唤醒等待在指定条件变量上的线程
    int count = 10;
    while (count != 0)
    {
        std::cout << "唤醒线程...唤醒倒计时：" << count-- << std::endl;

        // pthread_cond_broadcast(&cond);唤醒等待在指定条件变量上的所有线程
        pthread_cond_signal(&cond); // 唤醒等待在指定条件变量上的单个线程

        sleep(1);
    }

    std::cout << "停止唤醒！[最后一次唤醒]" << std::endl;
    quit = true;
    pthread_cond_broadcast(&cond);

    // 主线程阻塞等待其余线程
    for (int i = 0; i < THREAD_NUM; i++)
    {
        pthread_join(tids[i], nullptr);
        std::cout << "thread" << i + 1 << ": " << tids[i] << " quit " << std::endl;
    }

    // 销毁互斥锁和条件变量
    pthread_mutex_destroy(&mtx);
    pthread_cond_destroy(&cond);

    return 0;
}
